"use strict";

define('config', {
	api: location.href.startsWith("http://localhost:") ? "http://localhost:8080/rsms" : "https://api.cjprods.org/rsms"
});

define('url', {
	// break url into { base, arg, anchor }
	//
	// base   will be kept as is (no decodeURI being done)
	// arg    will be kept as is (no decodeURI being done)
	// anchor will be decodeURI.
	//
	// - "base"                     -> { "base", undefined, undefined }
	// - "base?arg"                 -> { "base", "?arg", undefined }
	// - "base#anchor"              -> { "base", undefined, "#anchor" }
	// - "base?arg#anchor"          -> { "base", "?arg", "#anchor" }
	// - "base#anchor?still#anchor" -> { "base", undefined, "#anchor?still#anchor" }

	split: function split(url) {
		var result = {};

		// anchor
		var anchor_at = url.indexOf("#");
		if (anchor_at !== -1) {
			result.anchor = decodeURI(url.substr(anchor_at));
			url = url.substr(0, anchor_at);
		}

		// arg
		var arg_at = url.indexOf("?");
		if (arg_at !== -1) {
			result.arg = url.substr(arg_at);
			url = url.substr(0, arg_at);
		}

		// base
		result.base = url;

		return result;
	},

	// break url arg part into object (key-value pair)
	// will decodeURIComponent
	// "?a=1%200&b=11" -> { a: "1 0", b: "11" }
	parse_arg: function parse_arg(arg) {
		if (arg == null) return {};

		var args = {};
		arg.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (_, name, value) {
			return args[decodeURIComponent(name)] = decodeURIComponent(value);
		});
		return args;
	},
	build_arg: function build_arg(args) {
		var arg = [];
		for (var name in args) {
			arg.push(encodeURIComponent(name) + "=" + encodeURIComponent(args[name]));
		}if (arg.length === 0) return "";
		return "?" + arg.join("&");
	},

	// parse url into base, arg, anchor args
	parse: function parse(url) {
		var result = this.split(url);
		result.args = this.parse_arg(result.arg);
		return result;
	},

	// build url from { base, arg, anchor }
	// { "http://example.com/", "?hi=10&yes=%2F", "#hello/" }
	//   -> "http://example.com/?hi=10&yes=%2F#hello%2F"
	// { "http://example.com/", { hi: 10, yes: "%2F" }, "#hello/" }
	//   -> "http://example.com/?hi=10&yes=%252F#hello%2F"
	build: function build(base, arg, anchor) {
		if (arg == null) arg = "";
		if (typeof arg !== 'string') arg = this.build_arg(arg);

		if (anchor == null) anchor = "";
		anchor = encodeURI(anchor);

		return base + arg + anchor;
	}
});

define('base64', {
	encode: function encode(x) {
		var x = btoa(unescape(encodeURIComponent(x))); // UTF-16 -> UTF-8-with-wchar -> base64
		x = x.replace(/[+/]/g, function (x) {
			return {
				"+": "-",
				"/": "_"
			}[x];
		});

		var npad = 0;
		while (x.endsWith("=")) {
			npad++;
			x = x.substr(0, x.length - 1);
		}
		return x + npad;
	},
	decode: function decode(x) {
		var npad = parseInt(x.substr(x.length - 1));
		x = x.substr(0, x.length - 1) + "=".repeat(npad);

		x = x.replace(/[-_]/g, function (x) {
			return {
				"-": "+",
				"_": "/"
			}[x];
		});
		return decodeURIComponent(escape(atob(x))); // base64 -> UTF-8-with-wchar -> UTF-16
	}
});

define('ajax', ['url'], function (url) {
	return {
		json: function json(post, base, args, ok, fail) {
			// normalize arguments
			if (ok == null) ok = function ok() {};
			if (fail == null) fail = function fail() {};

			// prepare callbacks
			var req = new XMLHttpRequest();
			req.onload = function () {
				var json = req.response;
				if (json == null) json = { error: "internal error" };
				if (json.error != null) fail(json.error);else ok(json.result);
			};
			req.onabort = function () {
				return fail("abort");
			};
			req.onerror = function () {
				return fail("error");
			};

			// fire!
			req.responseType = 'json';
			if (post) {
				req.open('POST', base);
				req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
				req.send(url.build_arg(args).substr(1)); // arg always begins with '?' or empty string
			} else {
					req.open('GET', url.build(base, args));
					req.send();
				}
		},
		get_json: function get_json(base, args, ok, fail) {
			this.json(false, base, args, ok, fail);
		},
		post_json: function post_json(base, args, ok, fail) {
			this.json(true, base, args, ok, fail);
		}
	};
});

define('api', ['config', 'url', 'base64', 'ajax'], function (config, url, base64, ajax) {
	return function () {
		var base = config.api;
		if (base == null) return;
		if (base.endsWith("/")) base = base.substr(0, base.length - 1);

		//----------------------------------------------------------------------
		// login and authentication

		var login = function login() {
			var loc = url.parse(location.href);
			delete loc.args.name;
			delete loc.args.username;
			var callback = url.build(loc.base, loc.args);
			location.href = url.build(base + "/login.html", { redirect: callback });
		};

		var roles = ['管理员', '教师', '学生', '教务处'];

		var parse_token = function parse_token(token) {
			// parse
			var shards = token.split('.');
			if (shards.length != 2) return;
			var raw_token = JSON.parse(base64.decode(shards[0]));
			// simple validation
			if (roles.indexOf(raw_token.role) === -1) return;
			if (raw_token.seq == null) return;

			return raw_token;
		};

		var init = function init() {
			var info = url.parse(location.href);
			var args = info.args;
			var token = info.anchor;
			if (token == null) return;
			if (args.name == null) return;
			if (args.username == null) return;

			token = token.substr(1);
			var raw_token = parse_token(token);
			if (raw_token == null) return;

			return {
				base: base,
				login: login,
				roles: roles,
				token: token,
				name: args.name,
				username: args.username,
				role: raw_token.role
			};
		};

		// check login
		var api = init();
		if (api == null) return login();

		//----------------------------------------------------------------------
		// APIs

		var zip_args = function zip_args(arg_names, args) {
			var result = {};
			arg_names.forEach(function (name, i) {
				var arg = args[i];
				if (arg == null) throw "bad api call: null not allowed in (" + name + ") of (" + arg_names + ")";
				if (name.startsWith('@')) {
					name = name.substr(1);
					result[name] = JSON.stringify(arg);
				} else {
					result[name] = arg;
				}
			});
			return result;
		};

		var make_scalar_api_invoker = function make_scalar_api_invoker(post, addr, arg_names) {
			return function () {
				for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
					args[_key] = arguments[_key];
				}

				var remain = args.length - arg_names.length;
				if (remain !== 1 && remain !== 2) throw "bad api call: expect " + (arg_names.length + 1) + " or " + (arg_names.length + 2) + " arguments (" + arg_names + ",callback,[update]), but " + args.length + " were given.";

				var callback = args[arg_names.length];
				if (typeof callback !== 'function') throw "bad api call: callback must be a function";
				var update = args[arg_names.length + 1];
				if (update == null) update = function update() {};
				if (typeof update !== 'function') throw "bad api call: optional 'update' must be a function";

				var ok = function ok() {
					return callback(null);
				};
				var fail = function fail(error) {
					if (error === 'denied') return login();

					console.error(error);
					if (error === 'bad argument: not unique') return callback("不唯一");
					if (error.endsWith('outdated')) {
						update();
						return callback("数据已过期，没有进行任何操作");
					}
					if (error.startsWith('bad argument:')) return callback("参数错误：" + error);
					callback("服务器错误");
				};

				var zargs = zip_args(arg_names, args);
				zargs.token = api.token;
				ajax.json(post, addr, zargs, ok, fail);
			};
		};

		var make_list_api_invoker = function make_list_api_invoker(addr, arg_names) {
			return function () {
				for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
					args[_key2] = arguments[_key2];
				}

				var zargs = zip_args(arg_names, args);
				zargs.token = api.token;

				return function () {
					var after = -1;
					var end = false;

					return function (callback) {
						if (typeof callback !== 'function') throw "callback must be a function";

						var ok = function ok(list) {
							if (list.length === 0) end = true;else after = list[list.length - 1].id;
							callback(list);
						};
						var fail = function fail(error) {
							if (error === 'denied') return login();
							console.error(error);
							callback(null);
						};

						if (end) setTimeout(function () {
							return callback([]);
						}); // setTimeout to emulate promise
						else {
								zargs.after = after;
								ajax.get_json(addr, zargs, ok, fail);
							}
					};
				};
			};
		};

		var make_api_invoker = function make_api_invoker(spec) {
			var arg_names = spec.split(/\s+/);
			var addr = arg_names.shift();

			var invoker;
			if (addr.startsWith('@')) {
				addr = addr.substr(1);
				invoker = make_list_api_invoker(base + "/api" + addr, arg_names);
			} else {
				var post = false;
				if (addr.startsWith('!')) {
					post = true;
					addr = addr.substr(1);
				}
				invoker = make_scalar_api_invoker(post, base + "/api" + addr, arg_names);
			}

			var name = addr.substr(1).split('/').join('_');
			return { name: name, invoker: invoker };
		};

		var populate_api = function populate_api(specs) {
			return specs.map(make_api_invoker).forEach(function (x) {
				return api[x.name] = x.invoker;
			});
		};

		populate_api(['/user/revoke/self', '/user/leave user', '/user/validate', '/user/password user value', '/user/password/self value', '/user/role user value', '/user/name user value', '!/user/add username password role name telephone', '@/user/list', '!/project/add name description budget', '!/project/activity/add project content cost', '@/project/activity/list/self project', '@/project/activity/list project', '!/project/report/add project content', '@/project/report/list/open project', '@/project/report/list/middle project', '@/project/report/list/final project', '@/project/list', '@/project/list/self', '@/project/student/list project', '!/project/student/approve project @students', '/project/approve project', '!/project/reject project reason', '/project/report/approve report', '!/project/report/reject report reason', '/student/apply project', '/student/cancel project', '@/student/list/project/pending', '@/student/list/project']);

		return api;
	};
});

define('app', [], function () {
	return function (angular, api) {
		var app = angular.module('rsms', ['ngMaterial', 'ngFileUpload']);

		app.config(function ($mdThemingProvider, $mdIconProvider) {
			$mdThemingProvider.theme('default').primaryPalette('blue');

			// load icons
			['home', 'menu', 'more-vert', 'account-switch', 'account-alert', 'account-key', 'account-multiple', 'account-convert', 'account-clipboard', 'account-network', 'back', 'refresh', 'plus', 'check', 'close', 'cancel', 'receipt', 'trending-up', 'comment', 'comment-more', 'motorbike', 'cash', 'list-ordered'].forEach(function (icon) {
				return $mdIconProvider.icon(icon, './icons/' + icon + '.svg');
			});
		});

		app.controller('app-controller', function ($mdSidenav, $mdMedia, $scope, $mdComponentRegistry, $mdToast, $mdDialog) {
			var _ = this;

			function popup(msg, delay) {
				var toast = $mdToast.simple().textContent(msg).position('top right');
				if (delay != null) toast = toast.hideDelay(delay);
				$mdToast.show(toast);
			}

			function prompt_dialog(info, open_from) {
				$mdDialog.show({
					templateUrl: 'prompt-dialog',
					clickOutsideToClose: true,
					controller: 'prompt-dialog-controller as dialog',
					openFrom: open_from,
					locals: { info: info }
				});
			}

			_.busy = null;
			_.name = api.name;
			_.username = api.username;
			_.role = api.role;
			_.api_base = api.base;
			_.roles = api.roles;

			_.set_busy = function (busy) {
				_.busy = busy == null ? "" : busy;
			};
			_.set_idle = function () {
				_.busy = null;
			};

			_.toolbar_show_icons = function () {
				return $mdMedia('gt-md');
			};
			_.menu_lock_open = function () {
				var big = $mdMedia('gt-xs');
				if (big && _.menu_opened()) _.close_menu();
				return big;
			};

			_.menu_opened = function () {
				return false;
			};
			_.open_menu = function () {};
			_.close_menu = function () {};

			$mdComponentRegistry.when('left').then(function (nav) {
				_.menu_opened = function () {
					return nav.isOpen();
				};
				_.open_menu = function () {
					nav.open();
				};
				_.close_menu = function () {
					nav.close();
				};
			});

			_.pages = [{
				name: '主页',
				icon: 'home',
				view: 'home'
			}, {
				name: '用户',
				icon: 'account-multiple',
				view: 'list',
				role: ['管理员'],
				list: api.user_list(),
				list_text: {
					major: function major(item) {
						return item.name;
					},
					desc: function desc(item) {
						return item.role;
					},
					minor: function minor(item) {
						return item.username;
					},
					menu: function menu(item) {
						return "用户名：" + item.username;
					}
				},
				add: {
					inputs: [{
						id: 'name',
						label: "姓名",
						type: "text",
						icon: 'account-clipboard'
					}, {
						id: 'role',
						label: "角色",
						selections: api.roles,
						icon: 'account-convert'
					}, {
						id: 'username',
						label: "用户名",
						type: "text",
						icon: 'account-multiple'
					}, {
						id: 'password',
						label: "密码",
						type: "password",
						icon: 'account-key'
					}, {
						id: 'telephone',
						label: "手机号",
						type: "number",
						icon: 'account-clipboard'
					}],
					action: function action(values, close) {
						_.set_busy();
						api.user_add(values.username, values.password, values.role, values.name, values.telephone, function (err) {
							if (err != null) {
								_.set_idle();
								popup(err);
							} else {
								_.set_idle();
								popup("用户 " + values.name + " (" + values.username + ") 添加成功");
								close();
								_.list_refresh();
							}
							$scope.$apply();
						});
					}
				},

				menu: [
				/*
    {
    	name: '修改姓名',
    	icon: 'account-clipboard',
    	click: function(item, menu, event) {
    		prompt_dialog({
    			label: '新姓名',
    			value: item.name,
    			icon: menu.icon,
    			text: `${item.name}(${item.username})`,
    			action_text: menu.name,
    			action_style: menu.style,
    			action: function(name) {
    				if (item.name === name) return;
    				_.set_busy();
    				api.user_name(item.id, name, function(err) {
    					if (err != null) {
    						_.set_idle();
    						popup(err);
    					}
    					else {
    						if (item.username === _.username) {
    							_.set_busy("姓名修改成功。请重新登录。");
    							setTimeout(api.login, 4000);
    						}
    						else {
    							_.set_idle();
    							item.name = name;
    							popup(item.username + " 的姓名已修改为：" + name);
    						}
    					}
    					$scope.$apply();
    				});
    			},
    		}, event.target);
    	},
    },
    */
				{
					name: '修改密码',
					icon: 'account-key',
					style: 'md-primary',
					disabled: 'item.username === app.username',
					click: function click(item, menu, event) {
						prompt_dialog({
							label: '新密码',
							type: 'password',
							icon: menu.icon,
							text: item.name + "(" + item.username + ")",
							action_text: menu.name,
							action_style: menu.style,
							action: function action(pwd) {
								_.set_busy();
								api.user_password(item.id, pwd, function (err) {
									if (err != null) {
										_.set_idle();
										popup(err);
									} else {
										_.set_idle();
										popup(item.username + " (" + item.name + ") 的密码修改成功");
									}
									$scope.$apply();
								});
							}
						}, event.target);
					}
				},
				/*
    {
    	name: '修改角色',
    	icon: 'account-convert',
    	style: 'md-warn',
    	disabled: 'item.username === app.username',
    	click: function(item, menu, event) {
    		prompt_d_selfialog({
    			selections: _.roles,
    			value: item.role,
    			icon: menu.icon,
    			text: `${item.name}(${item.username})`,
    			action_text: menu.name,
    			action_style: menu.style,
    			action: function(role) {
    				if (item.role === role) return;
    				_.set_busy();
    				api.user_role(item.id, role, function(err) {
    					if (err != null) {
    						_.set_idle();
    						popup(err);
    					}
    					else {
    						_.set_idle();
    						item.role = role;
    						popup(item.username + " (" + item.name + ") 现在是 " + role);
    					}
    					$scope.$apply();
    				});
    			},
    		}, event.target);
    	},
    },
    */
				{
					name: '删除',
					icon: 'cancel',
					style: 'md-accent',
					disabled: 'item.username === app.username',
					click: function click(item, menu, event) {
						prompt_dialog({
							text: "确定将 " + item.name + "(" + item.username + ") 标记为删除？此操作将无法撤销。",
							action_text: menu.name,
							action: function action() {
								_.set_busy();
								api.user_leave(item.id, function (err) {
									if (err != null) {
										_.set_idle();
										popup(err);
									} else {
										_.set_idle();
										popup(item.name + "(" + item.username + ") 已删除");
										_.list_refresh();
									}
									$scope.$apply();
								});
							}
						}, event.target);
					}
				}]
			}, {
				name: '科研项目',
				icon: 'trending-up',
				view: 'list',
				role: ['教师'],
				list: api.project_list_self(),
				list_text: {
					major: function major(item) {
						return item.name;
					},
					desc: function desc(item) {
						return item.state == 0 ? "待审批" : item.state == 1 ? "被拒绝" : "已批准";
					},
					minor: function minor(item) {
						return "￥" + item.budget;
					},
					menu: function menu(item) {
						return "申请于 " + item.date + "，" + item.description;
					},
					style: function style(item) {
						return item.state == 0 ? "" : item.state == 1 ? "color-no" : "color-yes";
					}
				},
				// TODO need to put description to somewhere
				add: {
					inputs: [{
						id: 'name',
						label: '项目名',
						type: 'text',
						icon: 'comment'
					}, {
						id: 'budget',
						label: '预算（人民币）',
						type: 'number',
						icon: 'cash',
						min: 0,
						max: 99999999.99,
						step: 0.01
					}, {
						id: 'description',
						label: '描述',
						type: 'text',
						icon: 'comment'
					}],
					action: function action(values, close) {
						_.set_busy();
						api.project_add(values.name, values.description, values.budget, function (err) {
							if (err != null) {
								_.set_idle();
								popup(err);
							} else {
								_.set_idle();
								popup("项目添加成功");
								close();
								_.list_refresh();
							}
							$scope.$apply();
						});
					}
				},
				menu: [{
					name: '项目成员',
					icon: 'list-ordered',
					disabled: 'item.state <= 1',
					click: function click(item) {
						var project = item.id;
						_.page_select({
							name: "项目成员",
							view: 'list',
							checkbox: item.state == 2,
							init: function init(page) {
								if (page.ack) {
									page.ack.selected = [];
									page.ack.project = project;
								}
							},
							list: api.project_student_list(project),
							list_text: {
								major: function major(item) {
									return item.name;
								},
								desc: function desc(item) {
									return item.username;
								},
								minor: function minor(item) {
									return '';
								},
								menu: function menu(item) {
									return "手机号： " + item.telephone;
								}
							},
							back: true,
							ack: item.state == 2 && {
								action: function action(ack) {
									_.set_busy();
									api.project_student_approve(ack.project, ack.selected, function (err) {
										if (err != null) {
											_.set_idle();
											popup(err);
										} else {
											_.set_idle();
											popup("成功");
											_.page_back();
										}
										$scope.$apply();
									});
								}
							}
						});
					}
				}, {
					name: '项目日志',
					icon: 'list-ordered',
					disabled: 'item.state <= 2',
					click: function click(item) {
						// TODO
						var project = item.id;
						_.page_select({
							name: "项目日志",
							view: 'list',
							list: api.project_activity_list(project),
							list_text: {
								major: function major(item) {
									return "￥" + item.cost;
								},
								desc: function desc(item) {
									return item.content;
								},
								minor: function minor(item) {
									return item.creator ? item.creator.name : '';
								},
								menu: function menu(item) {
									return "添加于 " + item.date;
								}
							},
							back: true,
							add: {
								inputs: [{
									id: 'cost',
									label: '花费（人民币）',
									type: 'number',
									icon: 'cash',
									min: 0,
									max: 99999999.99,
									step: 0.01
								}, {
									id: 'content',
									label: '梗概',
									type: 'text',
									icon: 'comment'
								}],
								action: function action(values, close) {
									_.set_busy();
									api.project_activity_add(project, values.content, values.cost, function (err) {
										if (err != null) {
											_.set_idle();
											popup(err);
										} else {
											_.set_idle();
											popup("日志添加成功");
											close();
											_.list_refresh();
										}
										$scope.$apply();
									});
								}
							}
						});
					}
				}, {
					name: '开题报告',
					disabled: 'item.state < 3',
					icon: 'list-ordered',
					click: function click(item) {
						// TODO
						var project = item.id;
						_.page_select({
							name: "开题报告",
							view: 'list',
							list: api.project_report_list_open(project),
							list_text: {
								major: function major(item) {
									return item.state == 1 ? "审批中" : item.state == 2 ? "被拒绝" : "已通过";
								},
								desc: function desc(item) {
									return item.content;
								},
								minor: function minor(item) {
									return item.date;
								},
								style: function style(item) {
									return item.state == 1 ? "" : item.state == 2 ? "color-no" : "color-yes";
								}
							},
							back: true,

							menu: [{
								name: '通过',
								icon: 'check',
								style: 'md-primary',
								disabled: 'item.state != 1',
								click: function click(item, menu, event) {
									prompt_dialog({
										text: "确定？",
										action_text: menu.name,
										action_style: menu.style,
										action: function action() {
											_.set_busy();
											api.project_report_approve(item.id, function (err) {
												if (err != null) {
													_.set_idle();
													popup(err);
												} else {
													_.set_idle();
													popup("已通过");
													_.list_refresh();
												}
												$scope.$apply();
											}, _.list_refresh);
										}
									}, event.target);
								}
							}, {
								name: '拒绝',
								icon: 'close',
								style: 'md-accent',
								disabled: 'item.state != 1',
								click: function click(item, menu, event) {
									prompt_dialog({
										text: "确定？",
										label: "理由",
										icon: 'comment',
										action_text: menu.name,
										action_style: menu.style,
										action: function action(reason) {
											_.set_busy();
											api.project_report_reject(item.id, reason, function (err) {
												if (err != null) {
													_.set_idle();
													popup(err);
												} else {
													_.set_idle();
													popup("已拒绝");
													_.list_refresh();
												}
												$scope.$apply();
											}, _.list_refresh);
										}
									}, event.target);
								}
							}]
						});
					}
				}, {
					name: '中期报告',
					disabled: 'item.state < 4',
					icon: 'list-ordered',
					click: function click(item) {
						// TODO
						var project = item.id;
						_.page_select({
							name: "中期报告",
							view: 'list',
							list: api.project_report_list_middle(project),
							list_text: {
								major: function major(item) {
									return item.state == 1 ? "审批中" : item.state == 2 ? "被拒绝" : "已通过";
								},
								desc: function desc(item) {
									return item.content;
								},
								minor: function minor(item) {
									return item.date;
								},
								style: function style(item) {
									return item.state == 1 ? "" : item.state == 2 ? "color-no" : "color-yes";
								}
							},
							back: true,

							menu: [{
								name: '通过',
								icon: 'check',
								style: 'md-primary',
								disabled: 'item.state != 1',
								click: function click(item, menu, event) {
									prompt_dialog({
										text: "确定？",
										action_text: menu.name,
										action_style: menu.style,
										action: function action() {
											_.set_busy();
											api.project_report_approve(item.id, function (err) {
												if (err != null) {
													_.set_idle();
													popup(err);
												} else {
													_.set_idle();
													popup("已通过");
													_.list_refresh();
												}
												$scope.$apply();
											}, _.list_refresh);
										}
									}, event.target);
								}
							}, {
								name: '拒绝',
								icon: 'close',
								style: 'md-accent',
								disabled: 'item.state != 1',
								click: function click(item, menu, event) {
									prompt_dialog({
										text: "确定？",
										label: "理由",
										icon: 'comment',
										action_text: menu.name,
										action_style: menu.style,
										action: function action(reason) {
											_.set_busy();
											api.project_report_reject(item.id, reason, function (err) {
												if (err != null) {
													_.set_idle();
													popup(err);
												} else {
													_.set_idle();
													popup("已拒绝");
													_.list_refresh();
												}
												$scope.$apply();
											}, _.list_refresh);
										}
									}, event.target);
								}
							}]
						});
					}
				}, {
					name: '结题报告',
					disabled: 'item.state < 5',
					icon: 'list-ordered',
					click: function click(item) {
						// TODO
						var project = item.id;
						_.page_select({
							name: "结题报告",
							view: 'list',
							list: api.project_report_list_final(project),
							list_text: {
								major: function major(item) {
									return item.state == 1 ? "审批中" : item.state == 2 ? "被拒绝" : "已通过";
								},
								desc: function desc(item) {
									return item.content;
								},
								minor: function minor(item) {
									return item.date;
								},
								style: function style(item) {
									return item.state == 1 ? "" : item.state == 2 ? "color-no" : "color-yes";
								}
							},
							back: true,

							menu: [{
								name: '通过',
								icon: 'check',
								style: 'md-primary',
								disabled: 'item.state != 1',
								click: function click(item, menu, event) {
									prompt_dialog({
										text: "确定？",
										action_text: menu.name,
										action_style: menu.style,
										action: function action() {
											_.set_busy();
											api.project_report_approve(item.id, function (err) {
												if (err != null) {
													_.set_idle();
													popup(err);
												} else {
													_.set_idle();
													popup("已通过");
													_.list_refresh();
												}
												$scope.$apply();
											}, _.list_refresh);
										}
									}, event.target);
								}
							}, {
								name: '拒绝',
								icon: 'close',
								style: 'md-accent',
								disabled: 'item.state != 1',
								click: function click(item, menu, event) {
									prompt_dialog({
										text: "确定？",
										label: "理由",
										icon: 'comment',
										action_text: menu.name,
										action_style: menu.style,
										action: function action(reason) {
											_.set_busy();
											api.project_report_reject(item.id, reason, function (err) {
												if (err != null) {
													_.set_idle();
													popup(err);
												} else {
													_.set_idle();
													popup("已拒绝");
													_.list_refresh();
												}
												$scope.$apply();
											}, _.list_refresh);
										}
									}, event.target);
								}
							}]
						});
					}
				}, {
					name: '取消项目',
					icon: 'cancel',
					style: 'md-accent',
					disabled: true, // TODO
					click: function click(item, menu, event) {
						prompt_dialog({
							text: "确定？",
							action_text: menu.name,
							action_style: menu.style,
							action: function action() {
								_.set_busy();
								api.sale_cancel(item.id, function (err) {
									if (err != null) {
										_.set_idle();
										popup(err);
									} else {
										_.set_idle();
										popup("￥" + item.budget + " 的业务已取消：" + item.purpose);
										item.state = '取消';
									}
									$scope.$apply();
								}, _.list_refresh);
							}
						}, event.target);
					}
				}]
			}, {
				name: '参与的项目',
				icon: 'trending-up',
				view: 'list',
				role: ['学生'],
				list: api.student_list_project(),
				list_text: {
					major: function major(item) {
						return item.name;
					},
					desc: function desc(item) {
						return item.description;
					},
					minor: function minor(item) {
						return item.budget ? "￥" + item.budget : '';
					},
					menu: function menu(item) {
						return item.creator.name + " 申请于 " + item.date;
					},
					style: function style(item) {
						return "color-yes";
					}
				},
				menu: [{
					// TODO
					name: '项目日志',
					icon: 'list-ordered',
					click: function click(item) {
						var project = item.id;
						_.page_select({
							name: "项目日志",
							view: 'list',
							list: api.project_activity_list_self(project),
							list_text: {
								major: function major(item) {
									return "￥" + item.cost;
								},
								desc: function desc(item) {
									return item.content;
								},
								minor: function minor(item) {
									return item.date;
								},
								menu: function menu(item) {
									return '';
								}
							},
							back: true,
							add: {
								inputs: [{
									id: 'cost',
									label: '花费（人民币）',
									type: 'number',
									icon: 'cash',
									min: 0,
									max: 99999999.99,
									step: 0.01
								}, {
									id: 'content',
									label: '梗概',
									type: 'text',
									icon: 'comment'
								}],
								action: function action(values, close) {
									_.set_busy();
									api.project_activity_add(project, values.content, values.cost, function (err) {
										if (err != null) {
											_.set_idle();
											popup(err);
										} else {
											_.set_idle();
											popup("日志添加成功");
											close();
											_.list_refresh();
										}
										$scope.$apply();
									});
								}
							}
						});
					}
				}, {
					// TODO
					name: '开题报告',
					disabled: 'item.state < 3',
					icon: 'list-ordered',
					click: function click(item) {
						var project = item.id;
						var report_state = item.report_state;
						var project_state = item.state;
						_.page_select({
							name: "开题报告",
							view: 'list',
							list: api.project_report_list_open(project),
							list_text: {
								major: function major(item) {
									return item.state == 1 ? "审批中" : item.state == 2 ? "被拒绝" : "已通过";
								},
								desc: function desc(item) {
									return item.content;
								},
								minor: function minor(item) {
									return item.date;
								},
								menu: function menu(item) {
									return item.content;
								},
								style: function style(item) {
									return item.state == 1 ? "" : item.state == 2 ? "color-no" : "color-yes";
								}
							},
							back: true,
							add: project_state != 3 || report_state == 1 || report_state == 3 ? null : { // FIXME dis add
								inputs: [{
									id: 'content',
									label: '开题报告',
									type: 'text',
									rows: 13,
									icon: 'comment'
								}],
								action: function action(values, close) {
									_.set_busy();
									api.project_report_add(project, values.content, function (err) {
										if (err != null) {
											_.set_idle();
											popup(err);
										} else {
											_.set_idle();
											popup("开题报告添加成功");
											close();
											_.page_back();
										}
										$scope.$apply();
									});
								}
							}
						});
					}
				}, {
					// TODO
					name: '中期报告',
					disabled: 'item.state < 4',
					icon: 'list-ordered',
					click: function click(item) {
						var project = item.id;
						var report_state = item.report_state;
						var project_state = item.state;
						_.page_select({
							name: "中期报告",
							view: 'list',
							list: api.project_report_list_middle(project),
							list_text: {
								major: function major(item) {
									return item.state == 1 ? "审批中" : item.state == 2 ? "被拒绝" : "已通过";
								},
								desc: function desc(item) {
									return item.content;
								},
								minor: function minor(item) {
									return item.date;
								},
								menu: function menu(item) {
									return item.content;
								},
								style: function style(item) {
									return item.state == 1 ? "" : item.state == 2 ? "color-no" : "color-yes";
								}
							},
							back: true,
							add: project_state != 4 || report_state == 1 || report_state == 3 ? null : { // FIXME dis add
								inputs: [{
									id: 'content',
									label: '中期报告',
									type: 'text',
									icon: 'comment'
								}],
								action: function action(values, close) {
									_.set_busy();
									api.project_report_add(project, values.content, function (err) {
										if (err != null) {
											_.set_idle();
											popup(err);
										} else {
											_.set_idle();
											popup("中期报告添加成功");
											close();
											_.page_back();
										}
										$scope.$apply();
									});
								}
							}
						});
					}
				}, {
					// TODO
					name: '结题报告',
					disabled: 'item.state < 5',
					icon: 'list-ordered',
					click: function click(item) {
						var project = item.id;
						var report_state = item.report_state;
						var project_state = item.state;
						_.page_select({
							name: "结题报告",
							view: 'list',
							list: api.project_report_list_final(project),
							list_text: {
								major: function major(item) {
									return item.state == 1 ? "审批中" : item.state == 2 ? "被拒绝" : "已通过";
								},
								desc: function desc(item) {
									return item.content;
								},
								minor: function minor(item) {
									return item.date;
								},
								menu: function menu(item) {
									return item.content;
								},
								style: function style(item) {
									return item.state == 1 ? "" : item.state == 2 ? "color-no" : "color-yes";
								}
							},
							back: true,
							add: project_state != 5 || report_state == 1 || report_state == 3 ? null : { // FIXME dis add
								inputs: [{
									id: 'content',
									label: '结题报告',
									type: 'text',
									icon: 'comment'
								}],
								action: function action(values, close) {
									_.set_busy();
									api.project_report_add(project, values.content, function (err) {
										if (err != null) {
											_.set_idle();
											popup(err);
										} else {
											_.set_idle();
											popup("结题报告添加成功");
											close();
											_.page_back();
										}
										$scope.$apply();
									});
								}
							}
						});
					}
				}]
			}, {
				name: '项目申报',
				icon: 'trending-up',
				view: 'list',
				role: ['学生'],
				list: api.project_list(),
				list_text: {
					major: function major(item) {
						return item.name;
					},
					desc: function desc(item) {
						return item.description;
					},
					minor: function minor(item) {
						return item.budget ? "￥" + item.budget : '';
					},
					menu: function menu(item) {
						return item.creator.name + " 创建于 " + item.date;
					},
					style: ''
				},
				menu: [{
					// TODO
					name: '申报参加',
					icon: 'check',
					style: 'md-primary',
					disabled: 'false',
					click: function click(item, menu, event) {
						prompt_dialog({
							text: "确定？",
							action_text: menu.name,
							action_style: menu.style,
							action: function action() {
								_.set_busy();
								api.student_apply(item.id, function (err) {
									if (err != null) {
										_.set_idle();
										popup(err);
									} else {
										_.set_idle();
										popup("已参加 " + item.name);
										_.list_refresh();
									}
									$scope.$apply();
								}, _.list_refresh);
							}
						}, event.target);
					}
				}]
			}, {
				name: '申报中的项目',
				icon: 'trending-up',
				view: 'list',
				role: ['学生'],
				list: api.student_list_project_pending(),
				list_text: {
					major: function major(item) {
						return item.name;
					},
					desc: function desc(item) {
						return item.description;
					},
					minor: function minor(item) {
						return item.budget ? "￥" + item.budget : '';
					},
					menu: function menu(item) {
						return item.creator.name + " 创建于 " + item.date;
					},
					style: function style(item) {
						return "";
					} },
				//"color-yes" : "color-no",
				menu: [{
					name: '取消申请',
					icon: 'cancel',
					style: 'md-accent',
					//disabled: 'item.state != null',
					click: function click(item, menu, event) {
						prompt_dialog({
							text: "确定？",
							action_text: menu.name,
							action_style: menu.style,
							action: function action() {
								_.set_busy();
								api.student_cancel(item.id, function (err) {
									if (err != null) {
										_.set_idle();
										popup(err);
									} else {
										_.set_idle();
										popup("项目 " + item.name + " 的申请已取消");
										//item.state = '取消';
										_.list_refresh();
									}
									$scope.$apply();
								}, _.list_refresh);
							}
						}, event.target);
					}
				}]
			}, {
				name: '项目审批',
				icon: 'trending-up',
				view: 'list',
				role: '教务处',
				list: api.project_list(),
				list_text: {
					major: function major(item) {
						return "￥" + item.budget;
					},
					desc: function desc(item) {
						return item.name;
					},
					minor: function minor(item) {
						return item.state == 1 ? "已拒绝" : item.state == 0 ? "" : "已批准";
					},
					menu: function menu(item) {
						return item.creator.name + " 申请于 " + item.date + "，" + item.description;
					},
					style: function style(item) {
						return item.state == 1 ? "color-no" : item.state == 0 ? "" : "color-yes";
					}
				},
				menu: [{
					name: '批准',
					icon: 'check',
					style: 'md-primary',
					disabled: 'item.state != 0',
					click: function click(item, menu, event) {
						prompt_dialog({
							text: "确定？",
							action_text: menu.name,
							action_style: menu.style,
							action: function action() {
								_.set_busy();
								api.project_approve(item.id, function (err) {
									if (err != null) {
										_.set_idle();
										popup(err);
									} else {
										_.set_idle();
										popup("已批准 " + item.creator.name + " 的项目");
										item.state = 2;
									}
									$scope.$apply();
								}, _.list_refresh);
							}
						}, event.target);
					}
				}, {
					name: '拒绝',
					icon: 'close',
					style: 'md-accent',
					disabled: 'item.state != 0',
					click: function click(item, menu, event) {
						prompt_dialog({
							text: "确定？",
							label: "理由",
							icon: 'comment',
							action_text: menu.name,
							action_style: menu.style,
							action: function action(reason) {
								_.set_busy();
								api.project_reject(item.id, reason, function (err) {
									if (err != null) {
										_.set_idle();
										popup(err);
									} else {
										_.set_idle();
										popup("拒绝了 " + item.creator.name + " 的项目");
										item.state = 1;
									}
									$scope.$apply();
								}, _.list_refresh);
							}
						}, event.target);
					}
				}, {
					name: '项目日志',
					icon: 'list-ordered',
					disabled: 'item.state <= 1',
					click: function click(item) {
						var project = item.id;
						_.page_select({
							name: "项目日志",
							view: 'list',
							list: api.project_activity_list(project),
							list_text: {
								major: function major(item) {
									return "￥" + item.cost;
								},
								desc: function desc(item) {
									return item.content;
								},
								minor: function minor(item) {
									return item.creator ? item.creator.name : '';
								},
								menu: function menu(item) {
									return "添加于 " + item.date;
								}
							},
							back: true
						});
					}
				}]
			}];

			_.page_select = function (page) {
				if (_.page === page) return;
				if (_.page != null && _.page.fini) _.page.fini(_.page);
				if (page.init) page.init(page);
				page.old_page = _.page;
				_.view = page.view;
				_.page = page;
				_.close_menu();
			};
			_.page_select(_.pages[0]);

			_.page_is = function (page) {
				return _.page === page;
			};

			_.view_is = function (view) {
				return _.view === view;
			};

			_.page_back = function () {
				if (_.page.old_page == null) return;
				_.page_select(_.page.old_page);
			};

			_.accessible = function (page) {
				if (page.role == null) return true;
				return page.role === _.role || page.role.indexOf(_.role) !== -1;
			};

			_.toolbar_icons = [{
				name: '修改我的密码',
				icon: 'account-key',
				style: '',
				style_collapse: 'md-primary',
				prompt: {
					label: "新密码",
					type: "password",
					text: _.role + " " + _.name + " " + _.username,
					action: function action(pwd) {
						_.set_busy();
						api.user_password_self(pwd, function (err) {
							if (err != null) {
								_.set_idle();
								popup(err);
							} else {
								_.set_busy("密码修改成功。需要重新登录。");
								setTimeout(api.login, 4000);
							}
							$scope.$apply();
						});
					}
				}
			}, {
				divider: true
			}, {
				name: '登出所有设备',
				icon: 'account-alert',
				style: 'md-warn md-hue-3',
				style_collapse: 'md-warn',
				click: function click() {
					_.set_busy();
					api.user_revoke_self(api.login);
				}
			}, {
				name: '切换用户',
				icon: 'account-switch',
				style: '',
				style_collapse: '',
				click: function click() {
					_.set_busy();
					api.login();
				}
			}];
			_.toolbar_icon_click = function (icon, event) {
				if (icon.view != null) _.page_select(icon);else if (icon.prompt != null) {
					icon.prompt.action_text = icon.name;
					icon.prompt.icon = icon.icon;
					prompt_dialog(icon.prompt, event.target);
				} else icon.click(event);
			};

			_.loading = false;
			var list = {};
			_.list_refresh = function () {
				list = {
					api: list.api,
					next: list.api(),
					cache: [],
					done: false
				};
			};
			var list_load = function list_load() {
				var lst = list;
				if (lst.done) return;
				if (_.loading) return;
				_.loading = true;
				if (!$scope.$$phase) $scope.$apply();
				lst.next(function (items) {
					if (items == null) {
						popup('载入失败');
						lst.done = true;
					} else {
						if (items.length < 10) lst.done = true;
						items.forEach(function (item) {
							lst.cache.push(item);
						});
					}
					_.loading = false;
					$scope.$apply();
				});
			};
			var items = {};
			items.getItemAtIndex = function (i) {
				if (i < list.cache.length) return list.cache[i];
				list_load();
			};
			items.getLength = function () {
				return list.cache.length + (list.done ? 0 : 1);
			};
			_.list_items = function () {
				if (_.page.list == null) return;
				if (list.api !== _.page.list) {
					list.api = _.page.list;
					_.list_refresh();
				}
				return items;
			};
			_.list_add = function (ev, page) {
				$mdDialog.show({
					templateUrl: 'form-dialog',
					clickOutsideToClose: true,
					controller: 'form-dialog-controller as dialog',
					openFrom: ev.target,
					locals: { info: page.add, action_text: "添加" + page.name }
				});
			};
			_.list_ack = function (ev, page) {
				prompt_dialog({
					text: '确认吗？',
					action_text: "确认" + page.name,
					action: function action() {
						return page.ack.action(page.ack);
					}
				});
			};

			// checkbox
			_.exists = function (item) {
				var list = _.page.ack.selected;
				return list.indexOf(item) > -1;
			};

			_.toggle = function (item) {
				var list = _.page.ack.selected;
				var idx = list.indexOf(item);
				if (idx > -1) list.splice(idx, 1);else list.push(item);
			};
		});

		app.controller('prompt-dialog-controller', function ($mdDialog, info) {
			var _ = this;

			Object.assign(_, info);
			if (_.action_style == null) _.action_style = "md-primary";
			if (_.type == null) _.type = "text";

			_.close = function () {
				$mdDialog.hide();
			};

			_.action = function () {
				info.action(_.value);
				_.close();
			};
		});

		app.controller('form-dialog-controller', function ($mdDialog, info, action_text) {
			var _ = this;

			_.inputs = info.inputs;
			_.values = {};
			_.action_text = action_text;

			_.close = function () {
				$mdDialog.hide();
			};

			_.action = function () {
				info.action(_.values, _.close);
			};
		});
	};
});

require.config({
	waitSeconds: 0,
	paths: {
		'angular': 'angular/angular.min',
		'angular-aria': 'angular/angular-aria.min',
		'angular-animate': 'angular/angular-animate.min',
		'angular-messages': 'angular/angular-messages.min',
		'angular-material': 'angular/angular-material.min',
		'angular-file-upload': 'angular/ng-file-upload.min',
		'angular-file-upload-shim': 'angular/ng-file-upload-shim.min'
	},
	shim: {
		'angular': { 'exports': 'angular' },
		'angular-aria': ['angular'],
		'angular-animate': ['angular'],
		'angular-messages': ['angular'],
		'angular-material': ['angular', 'angular-aria', 'angular-animate', 'angular-messages'],
		'angular-file-upload': ['angular', 'angular-file-upload-shim']
	},
	priority: ['api', 'app', 'angular']
});

// two-staged require
// so that login check will be earlier
require(['api', 'app'], function (make_api, app) {
	// init api
	var api = make_api();
	if (api == null) return;
	api.user_validate(function () {}); // validate user so that user's time may not be wasted.

	require(['angular', 'angular-material', 'angular-file-upload'], function (angular) {
		// fuck ARIA off
		(function (warn) {
			return console.warn = function (x) {
				return x.startsWith('ARIA:') ? null : warn(x);
			};
		})(console.warn);

		// init app
		angular.element(document.querySelector('html')).ready(function () {
			app(angular, api);
			angular.bootstrap(document, ['rsms']);

			// hide preloading
			var preloading = document.querySelector('#preloading');
			preloading.parentElement.removeChild(preloading);
		});

		// TODO: remove these on release
		window.api = api;
	});
});

define("init", function () {});

